module nazo.string;
/**
 * 文字列を扱う汎用API
 * History:
 *          0.0.0.4 findBeforesWithoutLastの追加、cosmetics
 *          0.0.0.3 joinのdelegate版追加
 *          0.0.0.2 getAfterの対応
 *          0.0.0.1 バージョン付け開始
 * Authors: Nazo
 * Version: 0.0.0.4
 * License: Public Domain
 */
public import std.string;
import std.contracts;

///aがbから始まっているか
bool startWith(string a,string b){
  if(a.length<b.length)return false;
  return cast(bool)(a[0..b.length]==b);
}

///strの中にcがあればstr[rfind(str,c)+1..$]を返しそれ以外ならstrを返す
static string getAfter(string str,char c){
  int s=std.string.rfind(str,c);
  if(s==-1)return str;
  return str[s+1..$];
}

///strの中にcがあればstr[rfind(str,c)+1..$]を返しそれ以外ならstrを返す
static string getAfter(string str,string c){
  int s=std.string.rfind(str,c);
  if(s==-1)return str;
  return str[s+1..$];
}

///strの中にcがあればstr[0..find(str,c)]を返しそれ以外ならstrを返す
static string getBefore(string str,char c){
  int s=std.string.find(str,c);
  if(s==-1)return str;
  return str[0..s];
}

///strの中にcがあればstr[0..find(str,c)]を返しそれ以外ならstrを返す
static string getBefore(string str,string c){
  int s=std.string.find(str,c);
  if(s==-1)return str;
  return str[0..s];
}

///strの中にcがあればdg(str[b..find(str,c)]);b=find(str,c);を繰り返す。残ったらdg(str[b..$]);をする。
static void getBefores(string str,char c,void delegate(string) dg){
  uint ib;
  foreach(uint i,char s;str){
    if(c==s){
      dg(str[ib..i]);
      ib=i+1;
    }
  }
  if(str[ib..$]!="")dg(str[ib..$]);
}

///strの中にcがあればdg(str[b..find(str,c)]);b=find(str,c);を繰り返す。残ったらdg(str[b..$]);をする。dgの戻り値が0より上なら終了する。
static void getBefores(string str,char c,uint delegate(string) dg){
  uint ib;
  foreach(uint i,char s;str){
    if(c==s){
      if(dg(str[ib..i]))
        return;
      ib=i+1;
    }
  }
  if(str[ib..$]!="")dg(str[ib..$]);
}

///strの中にcがあればdg(str[b..find(str,c)]);b=find(str,c);を繰り返す。残ったらdg(str[b..$]);をする。
static void getAfters(string str,char c,void delegate(string) dg){
  uint ib = str.length;
  foreach_reverse(uint i,char s;str){
    if(c==s){
      dg(str[i+1..ib]);
      ib=i;
    }
  }
  if(ib>1)dg(str[0..ib]);
}

///strの中にcがあればdg(str[b..find(str,c)]);b=find(str,c);を繰り返す。残ったらdg(str[b..$]);をする。dgの戻り値が0より上なら終了する。
static void getAfters(string str,char c,uint delegate(string) dg){
  uint ib = str.length;
  foreach_reverse(uint i,char s;str){
    if(c==s){
      if(dg(str[i+1..ib]))
        return;
      ib=i;
    }
  }
  if(ib>1)dg(str[0..ib]);
}

///strの中にcがあればdg(str[b..find(str,c)]);b=find(str,c);を繰り返す。残ってもdg(str[b..$]);はしない。
static void getBeforesWithoutLast(string str,char c,void delegate(string) dg){
  uint ib;
  foreach(uint i,char s;str)
    if(c==s){
      dg(str[ib..i]);
      ib=i+1;
    }
}

///strの中にcがあればdg();を繰り返す。残ってもdg();はしない。
static void findBeforesWithoutLast(string str,char c,void delegate() dg){
  foreach(char s;str)
    if(c==s)
      dg();
}

///arrを繋げて一つの文字列にする
static string join(string[] arr...){
  char[] re;
  uint i;
  foreach(inout string a;arr){
    i+=a.length;
  }
  re.length=i;
  i=0;
  foreach(inout string a;arr){
    uint t=i+a.length;
    re[i..t]=a;
    i=t;
  }
  return assumeUnique(re);
}

///arrを繋げて一つの文字列にする
static void join(void delegate(string str) dg,string[] arr...){
  uint i;
  foreach(inout string a;arr)
    i+=a.length;

  scope char[] re=new char[i];
  i=0;
  foreach(inout string a;arr){
    uint t=i+a.length;
    re[i..t]=a;
    i=t;
  }
  dg(assumeUnique(re));
}

///strにarrの各要素を繋げる
static void join2(inout char[] str,string[] arr...){
  uint i;
  foreach(inout string a;arr){
    i+=a.length;
  }
  uint i2=str.length;
  str.length=str.length+i;
  foreach(inout string a;arr){
    uint t=i2+a.length;
    str[i2..t]=a;
    i2=t;
  }
}
